import gtk
from gtkmvc.view import View

from resizableimage import ResizableImage


def change_packing(widget,
        expand=None, fill=None, padding=None, pack_type=None):
    parent = widget.get_parent()
    packing = list(parent.query_child_packing(widget))

    if expand is not None:
        packing[0] = expand
    if fill is not None:
        packing[1] = fill
    if padding is not None:
        packing[2] = padding
    if pack_type is not None:
        packing[3] = pack_type

    parent.set_child_packing(widget, *tuple(packing))


class StatusManager:
    
    def __init__(self, textview, status_colors):
        self.textview = textview
        self.textbuffer = textview.get_buffer()
        self.status_mark = self.textbuffer.create_mark(
            'StatusMark', self.textbuffer.get_end_iter())
        #
        self.status_tags = {}
        tag_table = self.textbuffer.get_tag_table()
        for name, color in status_colors.items():
            tag = gtk.TextTag()
            tag.set_property('paragraph-background', color)
            tag_table.add(tag)
            self.status_tags[name] = tag

    def set(self, message, status=None):
        # Start new line.
        text = self.textbuffer.get_text(
            self.textbuffer.get_start_iter(),
            self.textbuffer.get_end_iter())
        if len(text) != 0:
            self.textbuffer.insert(self.textbuffer.get_end_iter(), '\n')
        if status is None:
            # Print plain line.
            self.textbuffer.insert(self.textbuffer.get_end_iter(), message)
        else:
            # Stylize the line.
            tag = self.status_tags[status]
            self.textbuffer.insert_with_tags(
                self.textbuffer.get_end_iter(), message, tag)
        self.textbuffer.move_mark(
            self.status_mark, self.textbuffer.get_end_iter())
        # Scroll to current status.
        self.textview.scroll_mark_onscreen(self.status_mark)

    def clear(self):
        self.textbuffer.set_text('')
        self.textbuffer.move_mark(
            self.status_mark, self.textbuffer.get_end_iter())


class DownloadTable(gtk.Table):

    def __init__(self, pano_details, zoom):
        self.cols, self.rows = pano_details.tilesAtZoom(zoom)
        gtk.Table.__init__(self, self.cols, self.rows, True)

        # Create array of progress bars.
        self.progressbars = []
        for x in range(self.cols):
            row = []
            for y in range(self.rows):
                progressbar = gtk.ProgressBar()
                progressbar.set_size_request(10, 20)
                progressbar.show()
                self.attach(
                    progressbar,
                    x, x+1, y, y+1,
                    xoptions=gtk.EXPAND|gtk.FILL,
                    yoptions=gtk.EXPAND|gtk.FILL,
                    xpadding=2,
                    ypadding=2)
                row.append(ProgressBar(progressbar))
            self.progressbars.append(row)

        self.worker = downloader.PanoramaDownloaderSimple(pano_details, zoom)
        self.downloaded = False
        self.pano_ready = False

    def run(self):
        """
        """
        #worker = downloader.PanoramaDownloader(pano_details, zoom)
        #worker.start()
        #while not worker.downloaded:
        #    pass
        #    # Update progress.
        #    #self.update_progress(worker, self.cols, self.rows)
        #    # Stop the UI from becoming non-responsive.
        #    #service_gui()
        ##self.update_progress(worker, self.cols, self.rows)

        self.worker.start()
        while not self.worker.downloaded:
            # Update progress.
            self.update_progress()
            # Stop the UI from becoming non-responsive.
            service_gui()
        self.update_progress()

        # Wait for image to be ready to display.
        while worker.isAlive():
            service_gui()
        image = worker.result
        return image


    def update_progress(self, worker):
        for x in range(self.cols):
            for y in range(self.rows):
                self.progressbars[x][y].update_percent(
                    worker.get_progress((x, y)))


class MyView(View):
    glade = 'streetplanets.glade'
    top = 'main_window'

    def __init__(self):
        View.__init__(self)

        self.status_manager = StatusManager(
            self['status_textview'],
            {'error': '#FF6666',
             'warning': '#FFCC33',
             'success': '#33CC33'})

        self['pano_image'] = ResizableImage()
        self['pano_image'].show()

        # Expanders for each step.
        self.step_expanders = (
            self['step1_expander'],
            self['step2_expander'])
        # Search buttons for different input methods.
        self.search_buttons = (
            self['address_search_button'],
            self['url_search_button'],
            self['lat_long_search_button'])
        # The sets of controls for taking input by each method.
        self.input_containers = (
            self['address_hbox'],
            self['url_hbox'],
            self['lat_long_hbox'],
            self['image_hbox'])

        # Connect signals to be handled completely internal to the View.
        self['step1_expander'].connect(
            'activate', self.on_step_expander_activate)
        self['step2_expander'].connect(
            'activate', self.on_step_expander_activate)
        self['input_method_combobox'].connect(
            'changed', self.on_input_method_combobox_changed)

        self.resolution_items = gtk.ListStore(str)
        self['resolution_combobox'].set_model(self.resolution_items)

        # Show first expander.
        self.show_only_step(self['step1_expander'])
        # Pick first input method.
        self.set_input_method(0)

        # Make the main window visible.
        self['main_window'].show()

    # ----------------------------------------------------------------
    # Control methods.
    # ----------------------------------------------------------------

    def hide_step(self, step):
        """Programmatically hide one of the steps."""
        change_packing(step, expand=False, fill=True)
        step.set_expanded(False)

    def hide_all_steps(self, skip=None):
        """Programmatically hide all of the steps."""
        for step in self.step_expanders:
            if step != skip:
                self.hide_step(step)

    def show_only_step(self, step):
        """Programmatically show one of the steps."""
        self.on_step_expander_activate(step)
        step.set_expanded(True)

    def set_input_method(self, index):
        """Programmatically chooses the input method."""
        self['input_method_combobox'].set_active(index)

    def set_download_container_sensitive(self, enable):
        """Enable/disable controls to download panorama."""
        self['pano_download_hbox'].set_sensitive(enable)

    def set_search_button_sensitive(self, enable):
        """Enable/disable all search buttons."""
        for button in self.search_buttons:
            button.set_sensitive(enable)

    def set_status(self, message, status=None):
        """Set status to an error state."""
        self.status_manager.set(message, status)

    def clear_status(self):
        self.status_manager.clear()

    def set_zoom_options(self, options):
        self.resolution_items.clear()
        for resolution in options:
            self.resolution_items.append([resolution])

    def set_zoom_selected(self, index):
        items = 0
        iter = self.resolution_items.get_iter_first()
        while iter is not None:
            iter = self.resolution_items.iter_next(iter)
            items += 1
        index = min(index, items - 1)
        self['resolution_combobox'].set_active(index)

    def set_pano_frame_widget(self, widget):
        self['pano_frame'].foreach(self['pano_frame'].remove)
        if widget:
            self['pano_frame'].add(widget)

    def create_download_table(self, rows, cols):
        table = gtk.Table(rows, cols, True)
        self.progressbars = []
        for y in range(rows):
            row = []
            for x in range(cols):
                progressbar = gtk.ProgressBar()
                progressbar.set_size_request(10, 20)
                table.attach(
                    progressbar,
                    x, x+1, y, y+1,
                    xoptions=gtk.EXPAND|gtk.FILL,
                    yoptions=gtk.EXPAND|gtk.FILL,
                    xpadding=2,
                    ypadding=2)
                row.append(progressbar)
            self.progressbars.append(row)
        table.show_all()
        self.set_pano_frame_widget(table)
        #self['download_table'] = table
        #self['pano_frame'].add(self['download_table'])

    def set_download_progress(self, x, y, fraction, text):
        self.progressbars[y][x].set_fraction(fraction)
        self.progressbars[y][x].set_text(text)

    def set_pano_image(self, image):
        self['pano_image'].set_from_PIL(image)
        self.set_pano_frame_widget(self['pano_image'])

    def set_download_text(self, text):
        label = gtk.Label(text)
        label.show()
        self.set_pano_frame_widget(label)

    # ----------------------------------------------------------------
    # Action listeners.
    # ----------------------------------------------------------------

    def on_step_expander_activate(self, widget, data=None):
        """Change which step dominates the form."""
        showing = not widget.get_expanded()
        if showing:
            self.hide_all_steps(skip=widget)
            # Grow the current step's expander.
            change_packing(widget, expand=True, fill=True)
        else:
            # All expanders will be hidden.
            for step_expander in self.step_expanders:
                change_packing(step_expander, expand=False, fill=True)

    def on_input_method_combobox_changed(self, widget, data=None):
        """Modify which input method to display."""
        selected = widget.get_active()
        for i, container in enumerate(self.input_containers):
            if i != selected:
                # Hide other input containers.
                container.hide()
        # Show the selected input container.
        self.input_containers[selected].show()
        # Show/hide the download controls.
        if selected == 3:
            self['pano_download_hbox'].hide()
        else:
            self['pano_download_hbox'].show()

